/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
 */

package autodispose;

import io.reactivex.rxjava3.annotations.Nullable;
import io.reactivex.rxjava3.exceptions.CompositeException;

import java.util.concurrent.atomic.AtomicReference;

/**
 * Terminal atomics for Throwable containers.
 */
final class ExceptionHelper {
    /**
     * A singleton instance of a Throwable indicating a terminal state for exceptions,
     * don't leak this.
     */
    private static final Throwable TERMINATED = new Termination();

    /**
     * Utility class.
     */
    private ExceptionHelper() {
        throw new IllegalStateException("No instances!");
    }

    static boolean addThrowable(AtomicReference<Throwable> field, Throwable exception) {
        for (; ; ) {
            Throwable current = field.get();

            if (current == TERMINATED) {
                return false;
            }

            Throwable update;
            if (current == null) {
                update = exception;
            } else {
                update = new CompositeException(current, exception);
            }

            if (field.compareAndSet(current, update)) {
                return true;
            }
        }
    }

    @Nullable
    static Throwable terminate(AtomicReference<Throwable> field) {
        Throwable current = field.get();
        if (current != TERMINATED) {
            current = field.getAndSet(TERMINATED);
        }
        return current;
    }

    /**
     * Synchronized thread.
     */
    static final class Termination extends Throwable {
        Termination() {
            super("No further exceptions");
        }

        @Override
        public synchronized Throwable fillInStackTrace() {
            return this;
        }
    }
}
